import os
import re
import uuid
from io import BytesIO, StringIO

from flask import Blueprint, request, jsonify, send_file
from flask_restful import Api, Resource
from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename

from models import *
from models import UpdateLog as UpdateLogModel
from util import jwt_encode, jwt_required, current_identity, UPLOAD_FILE, jwt_decode

api_db = Blueprint('api', __name__, 'api')
api = Api(api_db)
base_dir = os.getcwd()


# 登录
class LoginApi(Resource):
    def post(self):
        api_data = {
            'code': '-1',
        }
        username = request.form.get('username')
        password = request.form.get('password')
        print(request.form, password)
        if not all([username, password]):
            api_data['msg'] = '请填写完整'
            return api_data
        user = User.query.filter(User.username == username).first()
        if not user:
            api_data['msg'] = '请注册'
            return api_data
        flag = check_password_hash(user.password, password)
        if not flag:
            api_data['msg'] = '用户名或者密码错误'
            return api_data
        token = jwt_encode({'uid': user.id, 'name': user.username})
        # de_token = jwt_decode(token)
        # print(de_token)
        api_data['code'] = '200'
        api_data['msg'] = 'success'
        api_data['token'] = token
        api_data['user_id'] = user.id
        api_data['is_adm'] = user.if_adm
        api_data['username'] = user.username
        return api_data


# 注册
class RegisterApi(Resource):
    def post(self):
        api_data = {
            'code': '-1',
        }
        username = request.form.get('username')
        password = request.form.get('password')
        phone = request.form.get('phone')
        iden_type = request.form.get('type', '0')
        print(request.form, iden_type)
        if not all([username, password, phone, iden_type]):
            api_data['msg'] = '请填写完整'
            return api_data
        user = User.query.filter(User.username == username).first()
        if user:
            api_data['msg'] = '用户已存在'
            return api_data
        if not re.match(r"^1[3456789]\d{9}$", phone):
            api_data['msg'] = '手机号错误'
            return api_data
        if iden_type != 'admin':
            user = User(username=username, phone=phone, password=generate_password_hash(password))
            db.session.add(user)
            db.session.commit()
            api_data['code'] = '200'
            api_data['msg'] = 'success'
            return api_data
        else:
            user = User(username=username, phone=phone, password=generate_password_hash(password), if_adm=True)
            db.session.add(user)
            db.session.commit()
            api_data['code'] = '200'
            api_data['msg'] = 'success'
            return api_data


# token更新
class UpdateToken(Resource):
    @jwt_required
    def post(self):
        token = jwt_encode({'uid': current_identity.get('uid'), 'name': current_identity.get('name')})
        return jsonify(code='200', token=token)


# 产品添加
class ProjectAdd(Resource):
    @jwt_required
    def post(self):
        api_data = {
            'code': '-1',
        }
        token = request.headers.get('Authorization', None).split()[-1]
        product_name = request.form.get('name')
        product_key = request.form.get('key')
        desc = request.form.get('desc')
        if not all([token, product_name, desc]):
            api_data['msg'] = '请填写完整'
            return api_data
        if product_key == '':
            product_key = "".join(str(uuid.uuid4()).split("-")).upper()
        else:
            pro = Project.query.filter_by(key=product_key).first()
            if pro:
                api_data['msg'] = '错误不允许创建'
        try:
            decode_token = jwt_decode(token)
            user_id = decode_token['identity']['uid']
            if not user_id:
                api_data['msg'] = 'error'
                return api_data
            user = User.query.get(user_id)
            if not user:
                api_data['msg'] = 'error'
            if user.if_adm:
                api_data['msg'] = '管理员不能创建'
                return api_data
            project = Project(user_id=int(user_id), name=product_name, desc=desc, key=product_key)
            db.session.add(project)
            db.session.commit()
            api_data['code'] = '200'
            api_data['msg'] = 'success'
            return api_data
        except Exception as e:
            api_data['msg'] = 'error'
            return api_data


# 项目列表
class ProjectInfo(Resource):
    @jwt_required
    def get(self):
        datas = []
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        print(decode_token)
        user_id = decode_token['identity']['uid']
        if user_id == '':
            return {"code": '-1', 'msg': 'error'}
        user = User.query.get(user_id)
        if not user:
            return {"code": '-1', 'msg': 'error'}
        if user.if_adm:
            # 管理员
            project_infos = Project.query.all()
            for project_info in project_infos:
                user_id = project_info.user_id
                user = User.query.get(user_id)
                data = {'id': project_info.id, 'name': project_info.name, 'desc': project_info.desc,
                        'key': project_info.key, 'created_at': str(project_info.created_at),
                        'updated_at': str(project_info.updated_at), 'username': user.username},
                datas.append(data)
            result = {"code": '200', 'msg': 'success',
                      'data': datas}
            return result
        # 普通用户
        project_infos = Project.query.filter(Project.user_id == int(user_id)).all()
        for project_info in project_infos:
            data = {'id': project_info.id, 'name': project_info.name, 'desc': project_info.desc,
                    'key': project_info.key, 'created_at': str(project_info.created_at),
                    'updated_at': str(project_info.updated_at), 'username': user.username}
            datas.append(data)
        result = {"code": '200', 'msg': 'success',
                  'data': datas}
        return result


# 项目详情
class ProjectDetail(Resource):
    def get(self):
        api_data = {
            'code': '-1',
        }
        datas = []
        project_id = request.form.get('project_id')
        # 设备列表
        try:
            devices = Device.query.filter(project_id=int(project_id)).all()
            api_data['msg'] = 200
            api_data['msg'] = 'success'
            for device in devices:
                data = {'id': device.id, 'project_id': device.project_id, 'uuid': device.uuid,
                        'created_at': device.created_at, 'updated_at': device.updated_at}
                datas.append(data)
            api_data['data'] = datas
            return api_data
        except Exception as e:
            api_data['msg'] = e
            return api_data


# 固件升级
class ProjectUpgrade(Resource):
    @jwt_required
    def get(self):
        api_data = {
            'code': '-1',
            'msg': '升级错误',
        }
        datas = []
        project_id = int(request.args.get('project_id'))
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        user = User.query.get(user_id)
        if user.if_adm:
            api_data['msg'] = '管理员无权'
            return api_data

        try:
            firmware_all = Firmware.query.filter_by(project_id=project_id).all()
            for firmware in firmware_all:
                data = {'id': firmware.id, 'name': firmware.name, 'project_id': firmware.project_id,
                        'version': firmware.version, 'url': firmware.url, 'condition': firmware.condition,
                        'created_at': str(firmware.created_at)}
                datas.append(data)
            api_data['code'] = '200'
            api_data['msg'] = 'success'
            api_data['data'] = datas
            return api_data
        except Exception as e:

            return api_data

    # 新建固件
    @jwt_required
    def post(self):
        api_data = {
            'code': '-1',
            'msg': '升级错误',
        }
        project_id = request.form.get('project_id')
        name = request.form.get('name')
        version = request.form.get('version')
        condition = int(request.form.get('condition'))
        if condition not in [0, 1, 2]:
            return api_data
        file = request.files.get('files', None)
        if not file or file.filename == '':
            api_data['msg'] = 'null'
            return api_data
        filename = secure_filename(file.filename)
        # 文件格式效验

        file.save(os.path.join('./static', filename))

        file_path = os.path.join(base_dir, os.path.join('static', filename))

        oss = UPLOAD_FILE('/')
        osspath = oss.upload_file(content_name=filename, path=file_path)
        # 升级文件
        firmware = Firmware(project_id=int(project_id), name=name, version=version, url=osspath, condition=condition)
        # 升级日志
        device = Device.query.filter_by(project_id=project_id).first()
        pro = Project.query.get(device.project_id)
        user = User.query.get(pro.user_id)
        device_user_name = user.username
        device_project_name = pro.name
        update_log = UpdateLogModel(device_uuid=device.uuid, device_user_name=device_user_name,
                                    device_project_name=device_project_name, request_time=datetime.datetime.now(),
                                    request_version=version, response_code=200)
        try:
            db.session.add(update_log)
            db.session.commit()
        except Exception as e:
            print(e)
            api_data['msg'] = 'error'
            return api_data
        try:
            db.session.add(firmware)
            db.session.commit()
            api_data['code'] = '200'
            api_data['msg'] = 'success'
            if condition == 2:
                try:
                    f_obj = FirmwareDevices(firmware_id=firmware.id, device_id=device.id)
                    db.session.add(f_obj)
                    db.session.commit()
                except Exception as e:
                    print(e)
                    return api_data
            return api_data
        except Exception as e:
            api_data['msg'] = e
            return api_data


# 固件修改
class ProjectEdit(Resource):
    @jwt_required
    def post(self):
        firmware_id = request.form.get('id', None)
        condition = int(request.form.get('condition', None))
        print(condition)
        if condition is None or firmware_id is None:
            return jsonify(code="-1", msg="error")
        if condition not in [1, 0, 2]:
            return jsonify(code="-1", msg="error:condition not in '1,2,3'")
        try:
            firmware = Firmware.query.get(firmware_id)
            firmware.condition = condition
            db.session.commit()
            return jsonify(code="200", msg="ok")
        except Exception as e:
            print(e)
            return jsonify(code="-1", msg="error")


# 固件删除
class ProjectDel(Resource):
    # @jwt_required
    def post(self):
        api_data = {
            'code': '-1',
            'msg': '删除错误',
        }
        firmware_id = request.form.get('id')
        f_obj = Firmware.query.get(firmware_id)
        print(f_obj.url)
        file_name = f_obj.url.split('/')[-1]
        oss = UPLOAD_FILE('/')
        flag = oss.delete(file_name)
        if not flag:
            return api_data
        try:
            db.session.delete(f_obj)
            db.session.commit()
            api_data['code'] = '200'
            api_data['message'] = 'success'
        except Exception as e:
            pass
        return api_data


# 设备信息
class DeviceInfo(Resource):
    @jwt_required
    def get(self):
        api_data = {
            'code': '-1',
            'msg': '设备错误',
            'data': '',
        }
        datas = []
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        user = User.query.get(user_id)
        devices = Device.query.all()
        api_data['code'] = '200'
        api_data['msg'] = 'success'
        if user.if_adm:
            for device in devices:
                pro = Project.query.get(device.project_id)
                user = User.query.get(pro.user_id)
                pro = Project.query.filter(Project.id == device.project_id).first()
                data = {"username": user.username,
                        "device_data": {'id': device.id, 'project_name': pro.name, 'imei': device.uuid,
                                        'updated_at': str(device.updated_at), 'username': user.username}}
                datas.append(data)
            api_data['data'] = datas
            api_data['count'] = len(datas)
            return api_data
        try:
            for device in devices:
                print(device.project_id)
                pro = Project.query.filter(Project.id == device.project_id).first()

                data = {'id': device.id, 'project_name': pro.name, 'imei': device.uuid,
                        'updated_at': str(device.updated_at), 'username': User.query.get(pro.user_id).username}
                datas.append(data)
            api_data['data'] = datas
            return api_data
        except Exception as e:
            return api_data


# 升级日志
class UpdateLog(Resource):
    @jwt_required
    def get(self):
        api_data = {
            'code': '-1',
            'msg': '设备错误',
            'data': '',
        }
        datas = []
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        user = User.query.get(user_id)
        if user.if_adm:
            log_all = UpdateLogModel.query.all()
            for log in log_all:
                device = Device.query.filter_by(uuid=log.device_uuid).first()
                project = Project.query.get(device.project_id)
                user = User.query.get(project.user_id)
                firmware = Firmware.query.filter_by(project_id=project.id).first()
                datas.append({
                    'id': log.id,
                    'imei': log.device_uuid,
                    'username': user.username,
                    'project_name': project.name,
                    'request_time': str(log.request_time),
                    'name': firmware.name,
                    "version": firmware.version,

                })
            api_data['data'] = datas
        else:
            log_all = UpdateLogModel.query.filter_by(device_user_name=user.username).all()
            for log in log_all:
                device = Device.query.filter_by(uuid=log.device_uuid).first()
                project = Project.query.get(device.project_id)
                user = User.query.get(project.user_id)
                firmware = Firmware.query.filter_by(project_id=project.id).first()
                datas.append({
                    'id': log.id,
                    'imei': log.device_uuid,
                    'username': user.username,
                    'project_name': project.name,
                    'request_time': str(log.request_time),
                    'name': firmware.name,
                    "version": firmware.version,
                })
            api_data['data'] = datas
        api_data['code'] = 200
        api_data['msg'] = 'ok'
        return api_data



# 升级统计
class FirmwareStatistics(Resource):
    @jwt_required
    def get(self):
        api_data = {
            'code': '-1',
            'msg': 'error',
        }
        datas = []
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        user = User.query.get(user_id)
        if user.if_adm:
            pro_list = Project.query.all()
            for pro in pro_list:
                username = User.query.filter_by(user_id=pro.user_id).first()
                fir = Firmware.query.filter_by(project_id=pro.id).first()
                if not fir:
                    continue
                data = {
                    "fir_name": fir.name,
                    "product_name": pro.name,
                    "desc": "",
                    "username": username,
                    "version": fir.version,
                    "count": "",
                }
                datas.append(data)
            api_data['data'] = datas
        else:
            pro_list = Project.query.filter_by(user_id=user_id).all()
            for pro in pro_list:
                fir = Firmware.query.filter_by(project_id=pro.id).first()
                if not fir:
                    continue
                data = {
                    "fir_name": fir.name,
                    "product_name": pro.name,
                    "desc": "",
                    "username": user.username,
                    "version": fir.version,
                    "count": "",
                }
                datas.append(data)
            api_data['data'] = datas
        api_data['code'] = 200
        api_data['msg'] = 'ok'
        return api_data


# 设备转移
class DeviceAssign(Resource):
    @jwt_required
    def post(self):
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        user = User.query.get(user_id)
        if user:
            uuid = request.form.get('uuid')
            phone = request.form.get('phone')
            device = Device.query.filter_by(uuid=uuid).first()
            target_user = User.query.filter_by(phone=phone).first()
            if user == target_user:
                return jsonify(code='-1', msg=f'phone do not is self')
            if not target_user:
                return jsonify(code='-1', msg=f'not phone number:{phone}')
            project = Project.query.get(device.project_id)
            project.user_id = target_user.id
            db.session.commit()
            try:
                assign_task = AssignTask(create_user_id=user.id, old_user_name=user.username,
                                         old_project_name=project.name,
                                         old_project_id=device.project_id, new_project_id=project.id,
                                         new_user_name=target_user.username,
                                         new_project_name=project.name, state='success')
                db.session.add(assign_task)
                db.session.commit()
                atd = AssignTaskDevice(task_id=assign_task.id, device_uuid=uuid)
                db.session.add(atd)
                db.session.commit()
                return jsonify(code="200", msg="success")
            except Exception as e:
                print(e)
                assign_task = AssignTask(create_user_id=user.id, old_user_name=user.username,
                                         old_project_name=project.name,
                                         new_user_name=target_user.username,
                                         old_project_id=device.project_id, new_project_id=project.id,
                                         new_project_name=target_user.username, state=f'error:{e}')
                db.session.add(assign_task)
                db.session.commit()
                return jsonify(code='-1', msg='error')
        return jsonify(code='-1', msg='token error')

    @jwt_required
    def get(self):
        datas = []
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        assign_task_all = AssignTask.query.filter_by(create_user_id=user_id).all()
        for assign in assign_task_all:
            user = User.query.get(assign.create_user_id)
            pro = Project.query.get(assign.old_project_id)
            assign_task_device_all = AssignTaskDevice.query.filter_by(task_id=assign.id).all()
            imei_list = []
            for atd in assign_task_device_all:
                imei_list.append(atd.device_uuid)
            data = {
                "create_user": user.username,
                "created_at": assign.created_at,
                "username": user.username,
                "product_name": pro.name,
                "imei": imei_list,
                "error": assign.state
            }
            datas.append(data)
        return jsonify(code='200', msg='success', data=datas)


# 获取device列信息
class GetDeviceColInfo(Resource):
    @jwt_required
    def get(self):
        res = {
            'code': 0,
            'msg': 'error',
            'data': []
        }
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        print(request.args)
        cols = request.args.get('data').split(',')
        for i in cols:
            if i not in ('id', 'project_id', 'uuid', 'created_at', 'updated_at'):
                res['msg'] = f'not filed `{i}`'
                return {}
        pro = Project.query.filter_by(user_id=user_id).all()
        for i in pro:
            devices = Device.query.filter_by(project_id=i.id).all()
            for j in devices:
                for col in cols:
                    res['data'].append({col: eval(f'j.{col}')})
        res['code'] = 200
        res['msg'] = 'ok'
        return res


class OutPutDeviceList(Resource):
    @jwt_required
    def get(self):
        token = request.headers.get('Authorization', None).split()[-1]
        decode_token = jwt_decode(token)
        user_id = decode_token['identity']['uid']
        proj = Project.query.filter_by(user_id=user_id).all()
        data = []
        for i in proj:
            for j in Device.query.filter_by(project_id=i.id).all():
                data.append(j)
        file = BytesIO()
        file.write(('\n'.join(['project,UUID,create time']+[f"{Project.query.get(i.project_id).name},{i.uuid},{i.created_at}" for i in data])).encode('utf-8'))
        file.seek(0)

        return send_file(file, as_attachment=True, attachment_filename="imei.csv")

class SetVersion(Resource):
    @jwt_required
    def post(self):
        api_data = {
            'code': '-1',
            'msg': '配置失败',
        }
        device_id = request.form.get('id')
        d_obj = Device.query.get(device_id)

        return api_data


# 用户
api.add_resource(LoginApi, '/user/login')
api.add_resource(RegisterApi, '/user/register')
api.add_resource(UpdateToken, '/token/update')
# 项目
api.add_resource(ProjectInfo, '/project')
api.add_resource(ProjectAdd, '/project/add')
api.add_resource(ProjectDetail, '/project/detail')
api.add_resource(ProjectUpgrade, '/project/upgrade')
api.add_resource(ProjectEdit, '/project/upgrade/edit')
api.add_resource(ProjectDel, '/project/upgrade/del')
# 设备
api.add_resource(DeviceInfo, '/device')
# 升级日志
api.add_resource(UpdateLog, '/update_log')
# 升级统计
api.add_resource(FirmwareStatistics, '/firmware_statistics')
# 设备转移
api.add_resource(DeviceAssign, '/device_assign')
# 获取设备列字段
api.add_resource(GetDeviceColInfo, '/get_device_col_info')
# 导出设备列表
api.add_resource(OutPutDeviceList, '/output_device_list')

# 配置版本
api.add_resource(SetVersion, '/set_version')